Mass balance — legacy RSMS vs new pipeline (investigation)
Legacy and new RSMS use the same engine executables (Neutshell, BLTM, CXPLT). When mass balance totals diverge, treat inputs to those executables as the first place to look, not the binaries.
Hypothesis checklist
NFQ / flow inputs
Compare neutral-flow files (or SQL vs API NFQ) for the same scenario date, river, and mile.
Action: Run new RSMS with an NFQ (or flow file) exported from or identical to the legacy run—e.g. pin the spill at river mile 475 and verify downstream steps match before chasing writer or Parquet parsing.CTL / scenario bag parity
ConfirmDISPERSION,DECAY_COEFFICIENT,SIMULATION_DURATION,SPILL_*,SPILL_RIVER_MILE/ tributary miles,GLOBAL_FLOW_MULTIPLIER, dead-zone lines, and timestep / segments / tolerances match line-for-line with legacy for the same scenario row.Time / timezone
Spill clock fields in the CTL (SPILL_DAY,SPILL_MONTH,SPILL_YEAR,SPILL_TIME) must match legacy in the scenario’s timezone. A one-hour shift changes NFQ sampling and can change mass routing.RMI and river mile index
Same.rmiandRiverMileIndex.csv(or blob equivalents) as legacy for the basin; any difference in reach lengths or junctions changes transport and summed mass splits.Post-engine processing
Only after inputs match: compare how new results derive river vs dead-zone vs total mass (mass_balance.jsonblobs +rsms_results_storageparsing) against legacy SQL reports or screenshots.
Suggested workflow
- Archive legacy CTL + NFQ +
.in(or exact NFQ source) for a reference scenario. - Run new worker with the same files (or byte-matched NFQ).
- If mass balance still differs, diff CTL and NFQ from new vs legacy; then diff CXPLT/BLTM outputs before the results writer.
Related implementation notes
- Scenario dispersion is stored as
dispersion_factor(API) and written asDISPERSIONin the CTL (legacy SimParams.DispersionFactor). - Ohio mainstem miles in the UI/geojson use a different convention than the CTL/plume axis; charts and map matching invert with 981.8 − RM for Ohio mainstem display only (see
docs//ohioRiverMile.js/mainstem_intersection.py).